﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using Kyoh.App.Crawler.Plugin;
using System.Collections.Specialized;
using System.Collections;

namespace Kyoh.App.Crawler.Contents
{
    [ComplexBindingProperties("DataSource", "DataMember")]
    partial class PluginListMenu : ContextMenuStrip
    {
        public PluginListMenu()
        {
            InitializeComponent();
        }

        public PluginListMenu(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        private object pluginManager = null;

        [DefaultValue("")]
        [RefreshProperties(RefreshProperties.Repaint)]
        [AttributeProvider(typeof(IListSource))]
        public object DataSource
        {
            get { return pluginManager; }
            set
            {
                if (pluginManager == value)
                    return;

                var notifier = pluginManager as INotifyCollectionChanged;
                if(notifier != null)
                    notifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(BindingSourceListChanged);
                var binder = pluginManager as IBindingList;
                if(binder!=null)
                    binder.ListChanged -= new ListChangedEventHandler(BindingListChanged);
                pluginManager = value;

                notifier = value as INotifyCollectionChanged;
                if (notifier != null)
                    notifier.CollectionChanged += new NotifyCollectionChangedEventHandler(BindingSourceListChanged);
                binder = pluginManager as IBindingList;
                if (binder != null)
                    binder.ListChanged += new ListChangedEventHandler(BindingListChanged);

                var list = pluginManager as IList;
                if (list == null)
                    return;
                RefreshItems(list.Cast<object>());
            }
        }

        private void BindingListChanged(object sender, ListChangedEventArgs e)
        {
            if (DesignMode)
                return;
            var list = DataSource as IList;
            if (list == null)
                return;
            ToolStripItem item;
            switch (e.ListChangedType)
            {
                case ListChangedType.ItemAdded:
                    item = CreateItem(list[e.NewIndex]);
                    if (item != null)
                        Items.Add(item);
                    break;
                case ListChangedType.ItemChanged:
                    Items.RemoveAt(e.NewIndex);
                    item = CreateItem(list[e.NewIndex]);
                    if (item != null)
                        Items.Insert(e.NewIndex, item);
                    break;
                case ListChangedType.ItemDeleted:
                    Items.RemoveAt(e.OldIndex);
                    break;
                case ListChangedType.ItemMoved:
                    item = Items[e.OldIndex];
                    Items.RemoveAt(e.OldIndex);
                    Items.Insert(e.NewIndex, item);
                    break;
                case ListChangedType.Reset:
                    RefreshItems(list.Cast<object>());
                    break;
            }
        }

        [RefreshProperties(RefreshProperties.Repaint)]
        [Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [DefaultValue("")]
        public string DataMember { get; set; }

        private void BindingSourceListChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (DesignMode)
                return;
            var list = DataSource as IList;
            if (list == null)
                return;
            ToolStripItem item;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    item = CreateItem(list[e.NewStartingIndex]);
                    if (item != null)
                        Items.Add(item);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    Items.RemoveAt(e.NewStartingIndex);
                    item = CreateItem(list[e.NewStartingIndex]);
                    if (item != null)
                        Items.Insert(e.NewStartingIndex, item);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    Items.RemoveAt(e.OldStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Move:
                    item = Items[e.OldStartingIndex];
                    Items.RemoveAt(e.OldStartingIndex);
                    Items.Insert(e.NewStartingIndex, item);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    RefreshItems(list.Cast<object>());
                    break;
            }
        }

        private ToolStripItem CreateItem(dynamic plugin)
        {
            var item = new ToolStripMenuItem { Text = plugin.Name };
            item.Click += (sender, e) => OnItemClicked(plugin);
            return item;
        }

        public new event PluginListMenuItemEventHandler ItemClicked;
        protected virtual void OnItemClicked(IPlugin plugin)
        {
            if (ItemClicked != null)
                ItemClicked(this, new PluginListMenuItemEventArgs(plugin));

        }

        private void BindingSourceBindingComplete(object sender, BindingCompleteEventArgs e)
        {
            var listSource = DataSource as IListSource;
            if (listSource == null)
                return;
            var list = listSource.GetList();
            if (list == null)
                return;
            RefreshItems(list.Cast<object>());
        }

        private void RefreshItems(IEnumerable<object> list)
        {
            if (list == null)
                return;
            Items.Clear();
            Items.AddRange(
                list
                .Select(CreateItem)
                .Where(i => i != null)
                .ToArray());
        }
    }
    public delegate void PluginListMenuItemEventHandler(object sender, PluginListMenuItemEventArgs e);
}
